import { message, Upload } from 'ant-design-vue'
import { defineComponent, ref, watch } from 'vue'

import { commonApi } from '@/apis'

import { DATA_TYPE, FILE_TYPE, STATUS } from './types'

export default defineComponent({
  name: 'UploadFile',
  props: {
    fileType: { type: [String], default: FILE_TYPE.IMAGE }, //文件类型 image,video,excel,pdf,all
    urls: { type: [String, Array], default: '' }, //数组或者用“,”分割的字符串v-model
    dataType: { type: [String], default: DATA_TYPE.STRING }, //urls的数据类型，DATA_TYPE.STRING 时用“,”分割
    maxSizeMB: { type: [Number], default: 200 }, //可选文件最大值MB
    maxLength: { type: [Number], default: 1 }, //最大可选数
    showUploadList: { type: [Boolean], default: true }, //是否显示上传列表
    hideUploadUpLimit: { type: [Boolean], default: true }, //到达最大可选数时是否隐藏上传图标。如果为false，新添加的文件会覆盖最早添加的
    imageSizeLimtWH: {
      type: [Array],
      default: () => {
        return [20000, 20000]
      }
    }, //文件类型为image时 校验宽高
    imageSizeLimtWeak: { type: [Boolean], default: true }, // 文件类型为image时 高宽弱校验 true：宽高比指定尺寸小就行 false：宽高和指定尺寸保持一致
    disabled: { type: [Boolean], default: false }
  },
  emits: ['change', 'update:urls'], //uploading,done,delete,error
  setup(props, { emit }) {
    const fileList = ref([] as any)
    setData()
    watch(
      () => props.urls,
      () => {
        setData()
      }
    )
    function setData() {
      if (props.urls && fileList.value.length == 0) {
        let arr
        if (props.dataType == DATA_TYPE.STRING) {
          if (Array.isArray(props.urls)) {
            throw 'DATA_TYPE.STRING 类型错误'
          }
          arr = props.urls.split(',')
        } else {
          arr = props.urls
        }
        if (arr && arr.length > 0) {
          fileList.value = arr.map((item, index) => {
            return {
              uid: '' + index,
              name: getFileNameFromUrl(item),
              status: 'done',
              url: item,
              thumbUrl: item
            }
          })
        }
      }
    }

    function getFileNameFromUrl(url) {
      return url.substring(url.lastIndexOf('/') + 1)
    }
    //上传回调
    function handleChange(info) {
      const tempfileList = [...info.fileList]
      const newTempfileList: any = []
      tempfileList.map(file => {
        if (file.status != STATUS.UNFIT_TYPE) {
          if (file.response && file.response.code == 20000) {
            file.url = file.response.data
          }
          newTempfileList.push(file)
        }
      })
      fileList.value = newTempfileList.slice(-props.maxLength)
      if (info.file.status === STATUS.UPLOADING) {
        emit('change', '', STATUS.UPLOADING)
      } else if (info.file.status === STATUS.DONE) {
        const resp = info.file.response
        if (resp.code == 20000) {
          dataChange()
          emit('change', fileList.value, STATUS.DONE)
        } else {
          message.error(resp.message)
          emit('change', '', STATUS.ERROR)
        }
      }
    }
    //校验文件
    function checkFile(file) {
      let fit = true
      switch (props.fileType) {
        case FILE_TYPE.IMAGE:
          fit = checkImage(file)
          break
        case FILE_TYPE.VIDEO:
          fit = checkVideo(file)
          break
        case FILE_TYPE.EXCEL:
          fit = checkExcel(file)
          break
        case FILE_TYPE.PDF:
          fit = checkPdf(file)
          break
        default:
          fit = checkSize(file, '文件')
          break
      }

      if (!fit) {
        file.status = STATUS.UNFIT_TYPE
      }
      if (props.fileType == FILE_TYPE.IMAGE && fit) {
        return new Promise((resolve, reject) => {
          imageWhCheck(file).then((result: any) => {
            if (result) {
              resolve('')
            } else {
              reject('')
            }
          })
        })
      } else {
        return fit
      }
    }

    //大小校验
    function checkSize(file, typeName) {
      const isLtSize = file.size / 1024 / 1024 < props.maxSizeMB
      if (!isLtSize) {
        message.error(`${typeName}最大支持${props.maxSizeMB}MB`)
      }
      return isLtSize
    }

    //excel校验
    function checkExcel(file) {
      const isExcel = file.name.toLowerCase().match(/\.(xls|xlsx)$/) != null
      if (!isExcel) {
        message.error('Excel格式不正确')
      }
      const isLtSize = checkSize(file, 'Excel')
      return isExcel && isLtSize
    }

    //pdf校验
    function checkPdf(file) {
      const isPDf = file.name.toLowerCase().match(/\.pdf$/) != null
      if (!isPDf) {
        message.error('pdf格式不正确')
      }
      const isLtSize = checkSize(file, 'pdf')
      return isPDf && isLtSize
    }

    //图片校验
    function checkImage(file) {
      const isImage =
        file.name.toLowerCase().match(/\.(jpeg|jpg|gif|png|webp|bmp)$/) != null
      if (!isImage) {
        message.error('图片格式不正确')
      }
      const isLtSize = checkSize(file, '图片')
      return isImage && isLtSize
    }

    //视频校验
    function checkVideo(file) {
      const isVideo = file.name.toLowerCase().match(/\.(mp4|m4v|mov)$/) != null
      if (!isVideo) {
        message.error('视频格式不正确')
      }
      const isLtSize = checkSize(file, '视频')
      return isVideo && isLtSize
    }

    //数据改变
    function dataChange() {
      const newUrls = fileList.value.map(item => item.url)
      if (props.dataType == DATA_TYPE.STRING) {
        emit('update:urls', newUrls.join(','))
      } else {
        emit('update:urls', newUrls)
      }
    }

    function imageWhCheck(file) {
      return new Promise((resolve, reject) => {
        const _URL = window.URL || window.webkitURL
        const img = new Image()
        img.src = _URL.createObjectURL(file)
        img.onload = function () {
          let whFit = true
          if (props.imageSizeLimtWeak) {
            whFit =
              //@ts-ignore
              img.width < props.imageSizeLimtWH[0] &&
              //@ts-ignore
              img.height < props.imageSizeLimtWH[1]
          } else {
            whFit =
              //@ts-ignore
              img.width == props.imageSizeLimtWH[0] &&
              //@ts-ignore
              img.height == props.imageSizeLimtWH[1]
          }
          if (!whFit) {
            message.error('图片尺寸不符合规范')
          }
          resolve(whFit)
        }
      })
    }

    return { fileList, handleChange, checkFile, dataChange }
  },
  render() {
    return (
      <Upload
        name="file"
        action={commonApi.uploadFileUrl}
        v-model:fileList={this.fileList}
        beforeUpload={this.checkFile}
        onChange={this.handleChange}
        disabled={this.$props.disabled}
        listType={
          this.$props.fileType == FILE_TYPE.IMAGE && this.showUploadList
            ? 'picture-card'
            : 'text'
        }
        showUploadList={this.$props.showUploadList}
        multiple={this.$props.maxLength > 1}
        remove={() => {
          setTimeout(() => {
            this.dataChange()
            this.$emit('change', this.fileList, STATUS.DELETE)
          }, 100)
          return true
        }}
      >
        {this.fileList.length < this.$props.maxLength
          ? this.$slots.default?.()
          : !this.$props.hideUploadUpLimit && this.$slots.default?.()}
      </Upload>
    )
  }
})
